/*
 * pml_qgram_grade.c
 *
 *  Created on: 2013-11-5
 *      Author: lius
 */
#include <stdio.h>
#include <stdlib.h>

extern char* Char2HexString(char a);

#define FILE_SIZE (1<<24)
typedef struct _gram_stat_{
	unsigned int count[FILE_SIZE];
}gram_stat_t;

gram_stat_t g_gram_stat = {};

int left_dis = 0;
int right_dis = 0;

int pml_load_db_file(char *database)
{
	FILE *fp = fopen(database, "rb+");
	if(fp == NULL)
	{
		return 0;
	}
	int len = fread((void *)&g_gram_stat, sizeof(int), FILE_SIZE, fp);
	if(len < FILE_SIZE)
	{
		fclose(fp);
		return -1;
	}
	fclose(fp);
	return 0;
}

int pml_save_db_file(char *database)
{
	FILE *fp = fopen(database, "wb");
	if(fp == NULL)
	{
		return 0;
	}
	int len = fwrite((void *)&g_gram_stat, sizeof(int), FILE_SIZE, fp);
	if(len < FILE_SIZE)
	{
		fclose(fp);
		return -1;
	}
	fclose(fp);
	return 0;
}

static double gram_score(char *gram, int len)
{
	const double perfect_score = 100.0;
	const double best_count  = 0.0;
	//const double worst_count = 4294967295.0;
	const double worst_count = 4294967.0;
	double res;
	//#define triple_grams(p) (((((unsigned int)p[0]) & 0xFF)<<16)|((((unsigned int)p[1]) & 0xFF)<<8)|(((unsigned int)p[2]) & 0xFF))
	#define triple_grams(p) (((((unsigned int)p[0]) & 0x7F)<<14)|((((unsigned int)p[1]) & 0x7F)<<7)|(((unsigned int)p[2]) & 0x7F))
	switch(len)
	{
	case 1:
		res = perfect_score - (((double)g_gram_stat.count[*gram])/worst_count)*perfect_score;
		break;
	case 2:
		res = perfect_score - (((double)g_gram_stat.count[*(unsigned short*)gram])/worst_count)*perfect_score;
		break;
	case 3:
		res = perfect_score - (((double)g_gram_stat.count[triple_grams(gram)])/worst_count)*perfect_score;
		break;
	default:
		res = 0.0;
		break;
	}
	return res;
}

static double gram_win_score(char *gram_win, int win_len, int q_len)
{
	int i = win_len - q_len;
	int j= 0;
	double score = 0;
	double tmp;
	for(;i >= 0; i--,j++)
	{
		tmp = gram_score(&gram_win[i], q_len);
		score += tmp/(1 << (tmp < 100.0 ? j+1 : j));
		//score += gram_score(&gram_win[i], q_len);
	}
	return score;
}

void pml_qgram_study(char *buff, int len, int q_len)
{
	int max_len = len - q_len + 1;
	int i= 0;
	double score = 0;
	const unsigned int max_count = 0xFFFFFFF;
	char *gram = buff;
	for(;i < max_len; i++,gram++)
	{
		switch(q_len)
		{
		case 1:
			g_gram_stat.count[*gram] = g_gram_stat.count[*gram] >= max_count ? g_gram_stat.count[*gram] : g_gram_stat.count[*gram] + 1;
			break;
		case 2:
			g_gram_stat.count[*(unsigned short*)gram] = g_gram_stat.count[*(unsigned short*)gram] >= max_count ? g_gram_stat.count[*(unsigned short*)gram] : g_gram_stat.count[*(unsigned short*)gram] + 1;
			break;
		case 3:
			g_gram_stat.count[triple_grams(gram)] = g_gram_stat.count[triple_grams(gram)] >= max_count ? g_gram_stat.count[triple_grams(gram)] : g_gram_stat.count[triple_grams(gram)] + 1;
			break;
		default:
			break;
		}
	}
	return;
}

int pml_qgram_select(char *pattern, int pattern_len, int w_len, int q_len, double *score)
{
	int max_loop = pattern_len - w_len + 1;
	int i = 0;
	double max_score = 0,cur_score;
	int best_pos = 0;
	for(; i < max_loop; i++)
	{
		cur_score = gram_win_score(&pattern[i], w_len, q_len);
		//printf("%f,", cur_score);
		if(cur_score > max_score)
		{
			max_score = cur_score;
			best_pos = i;
		}
	}
	if(left_dis < best_pos)
		left_dis = best_pos;
	if(right_dis < pattern_len - best_pos - 1)
		right_dis = pattern_len - best_pos - 1;

//	if(max_score > 100.0)
//	{
//		for(i = 0;i < pattern_len; i++)
//			printf("%s", Char2HexString(pattern[i]));
//		printf("\n");
//		//printf(",%f\n", max_score);
//	}
	//printf("%f\n", max_score);

	*score = max_score;
	return best_pos;
}

inline void pml_qgram_pos_print()
{
	printf("left_dis:%d;right_dis:%d\n", left_dis, right_dis);
}

